#include "AlgorithmManager.hpp"
#include "Algorithm.h"
#include "Algorithm_types.h"
#include "BufferImage.hpp"
#include "Client_types.h"
#include <chrono>
#include <exception>
#include <memory>
#include <spdlog/spdlog.h>
#include <stop_token>
#include <thread>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/protocol/TProtocol.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TTransport.h>
#include <yaml-cpp/yaml.h>

AlgorithmManager::AlgorithmManager() {}

AlgorithmManager::~AlgorithmManager() {}

void AlgorithmManager::Boot(const std::deque<ClientPara> &clientList_) {
  for (const auto &i : clientList_) {
    try {
      auto &obj = clientList.emplace_back(i.name, i.ipaddr, i.port);
      obj.funcGet = funcGetData;
      obj.funcSet = funcSendResult;
    } catch (const std::exception &e) {
      spdlog::warn("AlgorithmManager Can't connect to {} ,what{}, Ignore it",
                   i.name, e.what());
    }
  }
  spdlog::info("AlgorithmManager Boot Finish : Connect peers {}",
               clientList_.size());
}

AlgorithmManager::ClientObject::ClientObject(const std::string &name_,
                                             const std::string &ipaddr_,
                                             long port_) {
  name = name_;
  socket = std::shared_ptr<apache::thrift::transport::TTransport>(
      new apache::thrift::transport::TSocket(ipaddr_, port_));
  transport = std::shared_ptr<apache::thrift::transport::TTransport>(
      new apache::thrift::transport::TBufferedTransport(socket));
  protocol = std::shared_ptr<apache::thrift::protocol::TProtocol>(
      new apache::thrift::protocol::TBinaryProtocol(transport));
  client = new AlgorithmIPC::AlgorithmClient(protocol);
  transport->open();
  workThread = std::jthread([this](std::stop_token token) {
    while (!token.stop_requested()) {
      BufferImage img = funcGet();
      if (img.data == nullptr) {
        std::this_thread::sleep_for(std::chrono::seconds(5));
        continue;
      }
      long imgsize;
      switch (img.type) {
      case Thrift::ImageFormat::GERY:
        imgsize = img.width * img.height;
        break;
      case Thrift::ImageFormat::RGB8:
        imgsize = img.width * img.height * 3;
        break;
      default:
        spdlog::warn("Unknow Image Format,Please update programes");
      }
      std::string ret;
      AlgorithmIPC::ImageData data;
      data.width = img.width;
      data.height = img.height;
      data.format = static_cast<AlgorithmIPC::ImageFormat::type>(img.type);
      data.data = std::string((char *)img.data, imgsize);
      try {
        client->HandleImage(ret, data);
      } catch (const std::exception &e) {
        spdlog::info("Call remote target {} failed , {} Thread Exited", name,
                     e.what());
        break;
      }
      funcSet(name, ret);
    }
  });
}

AlgorithmManager::ClientObject::~ClientObject() {
  if (workThread.joinable()) {
    workThread.request_stop();
    workThread.join();
  }
}
